“我报名参加金石计划 1 期挑战——瓜分 10 万奖池,这是我的第 2 篇文章,点击查看活动详情 (opens new window)

# 前置知识

回答这个问题之前需要具备一些 webpack-cli 的前置知识。首先我们可以检验一下对 webpack-cli 的理解情况?

  1. 为什么要使用 webpack-cli?
  2. 怎么使用呢?
  3. 能否判断出什么样的情况下是使用了 webpack-cli,什么情况下是直接使用 wepack 的 Node.js API?
  4. 使用它有什么好处?
  5. 是必须要用的吗?
  6. 。。。

如果能回答出这些问题,说明对 webpack-cli 有一定的认识,如果有不明确的可以查阅一些资料,补充这部分的知识。

官方文档介绍

命令行接口(CLI):为了更合适且方便地使用配置,可以在 webpack.config.js 中对 webpack 进行配置。CLI 中传入的任何参数会在配置文件中映射为对应的参数。

https://webpack.js.org/api/cli (opens new window)

https://webpack.docschina.org/api/cli/ (opens new window)

# 使用 webpack-cli

index.js

const sum = require("./sum");
console.log(sum(6 + 9));
1
2

sum.js

function sum(a, b) {
  return a + b;
}
1
2
3

示例一:

命令行运行

npx webpack --entry ./index.js --output-path build
1

执行情况:

image.png

示例二:

webpack.config.js

const path = require("path");
module.exports = {
  entry: "./index.js",
  output: {
    path: path.resolve(__dirname, "build"),
  },
  mode: "none",
};
// npx webpack --entry ./index.js --output-path build
1
2
3
4
5
6
7
8
9

命令行运行

npx webpack
1

执行结果:

接下来想通过调试源码的方式,去看 webpack 与 webpack-cli 的工作流程。

# 开始调试

# 思路一

我们知道,在使用 webpack-cli 的时候,实际会去找 node_modules webpack、webpack-cli 依赖包 package.json 中定义的 bin 字段所对应的文件

bin 字段用来指定各个内部命令对应的可执行文件的位置

https://docs.npmjs.com/cli/v8/configuring-npm/package-json/#bin (opens new window)

webpack

在第 8 行打个断点

webpack-cli

第 5 行打断点

我自己在调试过程中,感觉这种方式需要不断去找去试,有时候可能就一不小心跳过关键代码了,就需要重新调试一遍。

所以就想着能不能换种思路跟代码,于是有了思路二,见下文。

# 思路二

观察控制台的日志

说明默认会自动执行计算编译时间,应该也是通过 stats 得到的,所以可以借用 Webpack 是如何计算编译时间的? (opens new window) 一文中找到的关键断点位置,打断点

重新通过 JavaScript Debug Terminal 运行命令 npx webpack,看是否能进入断点

进入断点处,发现左边调用堆栈有一堆东西,点进去看看,发现是 webpack Compiler、Compilation 等的一些执行,我们现在先不关心,因为我们要找 webpack-cli 做了些什么事情

将调用堆栈拖动到最底部,在这个关键位置(第 1789 行)打一个断点,猜测是在这里构建 compiler 对象,然后进行一系列打包,

断开调试,然后在重新输入 npx webpack 开启调试

进入断点处,观察左侧调用堆栈,出现了一些关键的调用

因为 webpack-cli 第 1789 行开始构建 compiler 对象,后续就要处理打包了,那说明之前就有 webpack-cli 处理命令行参数的相关逻辑,

这时候就可以从下往上依次看看调用情况,接下来就可以逐个打上断点,再从头调试一遍,基本就会比较清晰了,具体内容见下文。

# 调试分析

关键步骤截图并分析

  1. 首先在控制台执行 npx webpack 发生了什么

    • 如果正常安装了依赖,会去执行 webpack/bin/webpack.js
  2. 判断 webpack-cli 是否安装,没有安装则提示安装,如果安装了,就到标记 2 的位置,执行 runCli 函数,再执行到标记 3 的位置,require(path.resolve(path.dirname(pkgPath), pkg.bin[cli.binName])); 这里通过 requirewebpack-cli 引入并执行

  3. 进入到 node_modules\webpack-cli\bin\cli.js

  4. 中间这些过程省略,大家自行分析一下

  5. 执行到 node_modules\webpack-cli\lib\webpack-cli.js 中的 createCompiler 函数,这里面有一个关键点

    let config = await this.loadConfig(options);
    config = await this.buildConfig(config, options);
    
    1
    2
  6. 先进入到 loadConfig 函数中

    • 这里判断我们在 npx webpack 后面有没有跟对应的配置参数,如果有的话,走 if 里的逻辑,如果没有的话,走 else 里的逻辑;
    • 我们这个例子中,直接是 npx webpack,所以会走 else,else 内有 defaultConfigFiles,这几个就是 webpack-cli 的默认配置文件,然后会去解析里面的配置信息,得到 config
  7. 然后创建 compiler,接下来就正式开始编译工作了

  8. 进入到 node_modules\webpack\lib\webpack.js,执行 compiler.run()

Webpack 是如何计算编译时间的? (opens new window) 文中,是通过 Webpack 的 Node.js API 手动调用 compiler.run

# 补充知识点

# npx

npx commandname 执行流程

  1. 在 node_modules/.bin 目录下查找 commandname 命令是否存在,如果存在,就执行,如果不存在,到第 2 步;
  2. 在环境变量 $PATH 里,检查 commandname 是否存在,如果存在,就执行,如果不存在,到第 3 步;
  3. 将 commandname 下载到一个临时目录,使用以后再删除。

这里以项目中安装了 webpack 依赖包为例

  1. 控制台执行 npx webpack 命令
  2. 去找 node_modules/.bin 目录下去找有没有 webpack 命令,如果有,就执行它
    • windows 用户

补充:这里的 node_modules/.bin/webpack.cmd 是在 npm install webpack -D 的时候生成的,该文件 "%dp0%..\webpack\bin\webpack.js" 是在 webpack package.json 的 bin 字段指定的

  1. 执行 webpack/bin/webpack.js 文件

# 小结

本文通过对源码的调试,对 webpack-cli 应该有一定的认识

  1. 可以处理命令行参数
  2. 可以对 webpack 的默认配置文件进行处理

也就是说我们有三种方式可以让 webpack 工作:

  1. 不用 webpack-cli,使用 webpack Node.js API,
const webpack = require("webpack");
const path = require("path");

function build1() {
  return webpack({
    entry: "./index.js",
    output: {
      path: path.resolve(__dirname, "build"),
    },
    mode: "none",
  });
}

build1().run((err, stat) => {
  const startTime = stat.startTime;
  const endTime = stat.endTime;
  console.log("构建时间", endTime - startTime);
  // console.log("构建时间", stat.endTime - stat.startTime);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  1. 使用 webpack-cli,传入命令行参数

在控制台执行

npx webpack --entry ./index.js --output-path build --mode=none
1
  1. 使用 webpack-cli,使用配置文件进行配置

webpack.config.js

const path = require("path");
module.exports = {
  entry: "./index.js",
  output: {
    path: path.resolve(__dirname, "build"),
  },
  mode: "none",
};
1
2
3
4
5
6
7
8

# 参考

上次更新: 2024年3月10日星期日上午10点19分